#ifndef __timer_H__
#define __timer_H__

#include <iostream>
#include <map>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>

#include "threadPool.hpp"

class Timer
{
public:
    using ptr = std::shared_ptr<Timer>;

    //period  定时任务执行周期
    //circulation 定时任务是否循环执行
    Timer(uint64_t period = 0, bool circulation = false);

    ~Timer() = default;
    
    void SetCirculation(bool circulation) { m_circulation = circulation; }

    //设置定时器触发的时间点
    void SetRunTime();

    uint64_t GetPeriod() { return m_period; }

    uint64_t GetRunTime() { return m_runTime; }

    std::function<void()> GetFunc() { return m_fun; }

    bool GetCirculation() { return m_circulation; }

    void Stop() { m_circulation = false; }

    //获取当前时间
    static uint64_t GetNowTime();

    //设置回调函数
    template<typename F, typename... Args>
    void SetFunc(F&& f, Args&&... args);
private:
    std::function<void()> m_fun;    //回调函数
    uint64_t m_period;      //触发定时器的周期 - 毫秒
    uint64_t m_runTime;     //定时器触发的时间点 - 毫秒
    std::atomic_bool  m_circulation; //是否循环触发
};

template<typename F, typename... Args>
void Timer::SetFunc(F&& f, Args&&... args)
{
    this->m_fun = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
}



class TimerManager
{
public:
    TimerManager(uint32_t threadNum = std::thread::hardware_concurrency());
    ~TimerManager();

    //period  定时任务执行周期
    //circulation 定时任务是否循环执行
    //f     回调函数
    //args  回调函数参数
    template<typename F, typename... Args>
    Timer::ptr AddTask(uint64_t period, bool circulation, F&& f, Args&&... args);

    void Stop() { m_stop = false; }

private:
    void _Run();

private:
    std::multimap<uint64_t, Timer::ptr> m_tasks;    //定时器任务容器
    std::mutex m_taskMutex;                         //m_tasks锁
    std::condition_variable m_condition;            //条件变量
    std::thread m_thread;                           //任务管理线程
    std::atomic_bool m_stop;                        //是否停止定时器
    ThreadPool m_threadPool;                        //线程池
};


template<typename F, typename... Args>
Timer::ptr TimerManager::AddTask(uint64_t period, bool circulation, F&& f, Args&&... args)
{
    Timer::ptr timer = std::make_shared<Timer>(period, circulation);
    timer->SetFunc(std::forward<F>(f), std::forward<Args>(args)...);
    timer->SetRunTime();

    bool empty = false;
    uint64_t time = 0;

    {
        std::unique_lock<std::mutex> m_taskMutex;

        if(m_tasks.empty())
        {
            empty = true;
        }
        else
        {
            time = m_tasks.begin()->second->GetRunTime();
        }
        m_tasks.insert(std::make_pair(timer->GetRunTime(), timer));
    }

    if(empty || timer->GetRunTime() <= time)
    {
        m_condition.notify_all();
    }

    return timer;
}

#endif
